#include "downloadtasks.h"

#include <QDir>
#include <QEventLoop>
#include <QJsonDocument>
#include <QNetworkReply>
#include "osdeamonservice.h"

const QString otaPackagPath_ = "/opt/ota/down";
//Q_GLOBAL_STATIC(DownloadTasks,m_downloadTasks)
DownloadTasks::DownloadTasks(QObject *parent)
    : QObject{parent}
{
    setStatus(DownloadStatus::DS_Finished);
    m_timer_check = new QTimer;
    connect(m_timer_check,&QTimer::timeout,this,[&](){
        if(!m_downloadMap.isEmpty() && m_front == m_tail){
            cancelDownload();
        }
        m_tail = m_front;
    });
}

// DownloadTasks *DownloadTasks::Get()
// {
//     return m_downloadTasks;
// }

void DownloadTasks::cancelDownload()
{
    //TODO 全部取消下载
    for(auto& v : m_downloadMap){
        m_downloadMap.key(v)->abort();
    }
}

QFile *DownloadTasks::openFileForWrite(const QString &fileName)
{
    QFile* file = new QFile(fileName);
    if(!file->open(QIODevice::WriteOnly | QIODevice::Append)){
        qDebug() << QString("Unable to save the file %1: %2.").arg(QDir::toNativeSeparators(fileName), file->errorString());
        return nullptr;
    }
    return file;
}

void DownloadTasks::startRequest()
{
    OSDeamonService* osdaemon = qobject_cast<OSDeamonService*>(sender());
    m_queueSize = osdaemon->m_queueSize;
    osdaemon->m_fileSavePath.clear();
    osdaemon->setDlExistError(false);
    if(osdaemon->m_tasksQueue.size()<=0){
        qDebug()<<"> downlaod queue in null!";
        return;
    }
    setStatus(DownloadStatus::DS_Start);
    for(auto& v : osdaemon->m_tasksQueue){
        OSDeamonService::PckPathCheckCode pcc;
        QString url = v.value("file_url").toString();
        QString fileSize = QString::number(v.value("file_size").toInt());
        QString path = otaPackagPath_;
        QString md5Code = v.value("md5").toString();
        url.replace("\\","/");
        
        if (!QFileInfo(path).isDir()) {
            QDir dir;
            dir.mkpath(path);
        }
        
        QString savePath = QUrl::fromUserInput(url).fileName();
        savePath.prepend(path+'/');
        
        if(QFile::exists(savePath)){
            QFile::remove(savePath);
        }
        
        pcc.pckPath = savePath;
        pcc.md5Code = md5Code;
        osdaemon->m_fileSavePath.append(pcc);
        
        
        QFile* file = openFileForWrite(savePath);
        QNetworkReply* reply = m_qnam.get(QNetworkRequest(QUrl(url)));

        connect(reply,&QIODevice::readyRead,this,&DownloadTasks::onHttpReadyRead);
        connect(reply,&QNetworkReply::finished,this,&DownloadTasks::onHttpFinished);
        
        connect(reply,&QIODevice::destroyed,osdaemon,&OSDeamonService::onDownloadFinished);
        //测试使用
        connect(reply,&QNetworkReply::downloadProgress,this,&DownloadTasks::onNetworkReplyProgress);
        
        //添加进map
        m_downloadMap.insert(reply,file);
        m_downloadSizeMap.insert(reply,0.0);
        
        m_allPackageSize += fileSize.toULongLong();
    }
    m_tail = -1;
    quint64 time = osdaemon->configTimerout()/2;
    m_timer_check->start(time*1000);
    qDebug()<<"> Total size:"<<QString::number(m_allPackageSize);
}

void DownloadTasks::postHttp(const QString &http, const QJsonObject &jsobj)
{
    qDebug()<<"> postHttp() http:"<< http<<"request:"<<jsobj;
    QJsonDocument req_json(jsobj);
    QNetworkRequest request;
    request.setUrl(QUrl(http));
    request.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/json"));
    QSharedPointer<QNetworkReply> reply(m_qnam.post(request,req_json.toJson()));
    
    connect(reply.get(),&QNetworkReply::finished,this,[=](){
        int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).value<int>();
        if(reply->error() == QNetworkReply::NoError){
            QString result(reply->readAll());
            emit postReply(http,result,code);
            return;
        }
        emit postReply(http,QString(),code);
        qDebug()<<"> postHttp() error code:"<<code<<" error log:"<<reply->readAll()<<"\n"<<http;
    });
    return;
}

DownloadTasks::DownloadStatus DownloadTasks::status() const
{
    return m_status;
}

void DownloadTasks::setStatus(DownloadTasks::DownloadStatus newStatus)
{
    if(m_status != newStatus){
        m_status = newStatus;
    }
}


void DownloadTasks::onHttpFinished()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    QFile* file = m_downloadMap.value(reply);

    if(file && reply->bytesAvailable()){
        file->write(reply->readAll());
    }
    if(reply->error() == QNetworkReply::OperationCanceledError){
        qDebug() << ">"<<" func:"<<__func__<<" line:"<<__LINE__ << "cancel download";
        emit sigTimerout(QNetworkReply::OperationCanceledError);
    }
    else if(reply->error()){ // NoError 0
        QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
        qDebug() << ">"<<" func:"<<__func__<<" line:"<< "reply finished, statusCode:" << statusCode;
        //TODO 出现错误将错误信息写进日志里面
        qDebug() << ">"<<" func:"<<__func__<<" line:"<< QString("Download failed: %1.").arg(reply->errorString());
        emit sigAppearError();
    }
    
    if(file){
        file->close();
        file->reset();
        file->deleteLater();
    }
    --m_queueSize;
    if(m_queueSize>0)
        return;
    if(m_timer_check->isActive())
        m_timer_check->stop();
    setStatus(DownloadStatus::DS_Finished);
    for (auto it = m_downloadMap.begin(); it != m_downloadMap.end(); ++it) {
        QNetworkReply* reply = it.key();
        if (reply) {
            reply->deleteLater(); // 调用 deleteLater() 方法
        }
    }
    m_downloadMap.clear();
    m_downloadSizeMap.clear();
}

void DownloadTasks::onHttpReadyRead()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    QFile* file = m_downloadMap.value(reply);
    
    if(file){
        file->write(reply->readAll());
    }else{
        reply->abort();
    }
}

void DownloadTasks::onNetworkReplyProgress(qint64 bytesRead, qint64 totalBytes)
{
    Q_UNUSED(totalBytes)
    setStatus(DownloadStatus::DS_Loading);
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    m_downloadSizeMap[reply] = bytesRead;
    
    qreal recvSize  = 0.0;
    for(auto& v:m_downloadSizeMap)
        recvSize += v;
    m_front = recvSize;
    qreal progress = qreal(recvSize)/qreal(m_allPackageSize);

    qDebug()<<"download size:"<<QString::number(progress*100,'f',2);
    emit sigDownloadSche(QString::number(progress*100,'f',2));
}
